﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Xml.Serialization;

namespace Dycox.Reporting
{
    public class Table : BlockElement
    {
        //private const int UL_SIZES = 1, UL_CELLS = 2, UL_ALL = 0xf, UL_SUSPENDING = 0x100, UL_NONE = 0;

        public Table()
        {
            _rows = new TableRowCollection(this);
            _columns = new TableColumnCollection(this);
        }

        private TableLayoutInfo _layout;
        //private int _layoutStatus = UL_NONE;

        private TableRowCollection _rows;
        [XmlArray("rows"), XmlArrayItem("row", typeof(TableRow))]
        public TableRowCollection Rows
        {
            get { return _rows; }
        }

        private TableColumnCollection _columns;

        [XmlArray("columns"), XmlArrayItem("column", typeof(TableColumn))]
        public TableColumnCollection Columns
        {
            get { return _columns; }
        }

        private float _cellPadding;

        [XmlAttribute("cellPadding")]
        public float CellPadding
        {
            get { return _cellPadding; }
            set { _cellPadding = value; }
        }

        private SizeF _standardCellSize;

        [XmlAttribute("standardCellSize")]
        public SizeF StandardCellSize
        {
            get { return _standardCellSize; }
            set { _standardCellSize = value; }
        }


        internal void NotifyLayoutChanged(object obj)
        {
            InvalidateLayoutInfo();
        }

        internal void NotifyElementAdded(TableElement column)
        {
            InvalidateLayoutInfo();
        }

        internal void NotifyElementRemoved(TableElement column)
        {
            InvalidateLayoutInfo();
        }

        internal void NotifyCellAdded(TableCell cell)
        {
            InvalidateLayoutInfo();
        }

        internal void NotifyCellRemoved(TableCell cell)
        {
            InvalidateLayoutInfo();
        }

        private void InvalidateLayoutInfo()
        {
            _layout = null;
        }

        internal TableLayoutInfo Layout
        {
            get
            {
                if (_layout == null)
                    _layout = new TableLayoutInfo(this);
                return _layout;
            }
        }

        //private void UpdateLayout(int methods)
        //{
        //    if ((_layoutStatus & UL_SUSPENDING) == UL_NONE)
        //    {
        //        if ((methods & UL_SIZES) == UL_SIZES)
        //            _layout.UpdateWidthsAndHeights();
        //        if ((methods & UL_CELLS) == UL_CELLS)
        //            _layout.UpdateCellLayout();
        //    }
        //    else
        //        _layoutStatus |= methods;
        //}

        //public void SuspendLayout()
        //{
        //    if (_layoutStatus == UL_NONE)
        //        _layoutStatus = UL_SUSPENDING;
        //}

        //public void ResumeLayout()
        //{
        //    if ((_layoutStatus & UL_SUSPENDING) == UL_SUSPENDING)
        //    {
        //        int methods = _layoutStatus & UL_ALL;
        //        if (methods != UL_NONE)
        //            UpdateLayout(methods);
        //    }
        //}

        protected internal override SizeF GetClientSize(RenderingContext context)
        {
            var layout = Layout;
            return new SizeF(layout.ColumnWidths.Sum(), layout.RowHeights.Sum());
        }

        protected internal override void Render(RenderingContext context)
        {
            var layout = Layout;
            ElementStyle style = GetRuntimeStyle();
            BorderStyle bstyle = style.Border;
            float lineWidth = bstyle.LineWidth, padding = CellPadding;
            var phycells = layout.PhysicalCells;
            int len0 = phycells.GetLength(0), len1 = phycells.GetLength(1);
            float x, y = 0;
            float[] widths = layout.ColumnWidths, heights = layout.RowHeights;
            RectangleF bounds;

            for (int r = 0; r < len0; r++)
            {
                x = 0;
                for (int c = 0; c < len1; c++)
                {
                    PhysicalCell pc = phycells[r, c];

                    if (pc.Occupation == CellOccupation.Normal)
                    {
                        float w = 0, h = 0;
                        TableCell cell = pc.Cell;
                        if (cell == null)
                            continue;// cell = new TableCell();

                        for (int rs = 0; rs < cell.RowSpan; rs++)
                        {
                            int i = rs + r;
                            if (i < heights.Length)
                                h += heights[i];// +lineWidth;
                        }
                        for (int cs = 0; cs < cell.ColSpan; cs++)
                        {
                            int i = cs + c;
                            if (i < widths.Length)
                                w += widths[i];// +lineWidth;
                        }

                        bounds = new RectangleF(x, y, w, h);
                        bounds.Offset(Location);

                        BorderSides sides = BorderSides.None;

                        if (r < len0 - 1) sides |= BorderSides.Bottom;
                        if (c < len1 - 1) sides |= BorderSides.Right;

                        RenderTableCell(context, cell, bounds, sides, padding);
                    }
                    x += widths[c];// +lineWidth;
                }
                y += heights[r];// +lineWidth;
            }

            ReportPaint.RenderBorders(context, GetBounds(context), style.Border);
        }

        private void RenderTableCell(RenderingContext context, TableCell cell, RectangleF bounds, BorderSides sides, float padding)
        {
            ElementStyle style = cell.GetRuntimeStyle();
            ReportPaint.RenderBackground(context, bounds, style.Background);

            RectangleF textRect = bounds;
            textRect.Inflate(-padding, -padding);

            string text = cell.Text;
            if (!cell.DisableEval)
                text = context.EvalString(text);

            ReportPaint.DrawString(context, text, textRect, style);

            ReportPaint.RenderBorders(context, bounds, style.Border, sides);
        }

    }
}
